#ifndef __NETWORK_H__
#define __NETWORK_H__

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "list.h"
#include "lock.h"
#include "wait.h"
#include "elog.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/prctl.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include "utils.h"
#include "fifo.h"

#define MAX_MSG_LENGTH		1024
#define NET_FIFO_DEPTH		0x800000

#define MAX_TCP_CLIENT_NUM 8

enum NETWORK_TYPE
{
    NETWORK_TYPE_UDP = 0,
    NETWORK_TYPE_TCP,
    NETWORK_TYPE_TCP_CLIENT,
};

struct net_frame {
	uint8_t buffer[MAX_MSG_LENGTH];
	uint16_t length;
};

struct tcp_client {
	struct list_head head;
	int running_flag;
    pthread_t pid;
    int id;
    int is_alive;
    int socket;
    int acceptfd;
    struct sockaddr_in clientaddr;
    void *context;
};

struct net_config {
    uint32_t enable;
    uint32_t type;
    char dst_ip[32];
    uint32_t local_port;
    uint32_t dst_port;
    uint32_t max_client;
};

struct network;

enum NETWORK_EVENT
{
    NETWORK_EVENT_NONE = 0,
    NETWORK_EVENT_RECV,
    NETWORK_EVENT_ACCEPT,
    NETWORK_EVENT_MAX,
};

typedef int32_t (*network_event_notify)(struct network*, int32_t, void*, void*);

struct network_event_action
{
    network_event_notify notify;
    void* object;
    struct network_event_action* next;
};

struct network_operation
{
    int32_t (*init)(struct network*);
    int32_t (*release)(struct network*);
    
    int32_t (*start)(struct network*, struct net_config *);
    int32_t (*stop)(struct network*);

    int32_t (*udp_write)(struct network*, uint8_t*, uint32_t);
    int32_t (*tcp_write)(struct network*, uint8_t*, uint32_t);
    int32_t (*write_fifo)(struct network* pnetwork, uint8_t* data, uint32_t len);
    
    int32_t (*put_client)(struct network*, struct list_head*, struct tcp_client*);
	struct tcp_client* (*get_client)(struct network*, struct list_head*);

    int32_t (*register_notify)(struct network*, int32_t, network_event_notify notify, void*);
    int32_t (*unregister_notify)(struct network*, int32_t, void*);
    int32_t (*trigger_notify)(struct network*, int32_t, void*);
};

struct network
{
    struct list_head head;
    wait_t wait;
    lock_t lock;
    lock_t notify_lock;

    int running_flag;
    pthread_t pid;

    uint8_t id;
    uint8_t enable;

    struct network_operation* op;
    struct network_event_action *paction[NETWORK_EVENT_MAX];

    /*private*/
    int tx_running_flag;
    pthread_t tx_pid;
    int socket;
    struct sockaddr_in targetaddr;
    struct sockaddr_in localaddr;
    struct ip_mreqn group;
    fifo_t tx_fifo;
    uint8_t tx_buffer[NET_FIFO_DEPTH];
    
    int tcp_server_flag;
    pthread_t tcp_server_pid;

    /*public*/
    struct net_config *pcfg;
    
    struct list_head tcp_free_queue;
    struct list_head tcp_busy_queue;
    struct tcp_client client[MAX_TCP_CLIENT_NUM];
    uint8_t client_num;
};

int32_t create_init_network(struct network** pnetwork);
void release_destroy_network(struct network* pnetwork);
        
#endif
